package com.ldg.seckill.service.impl;

import com.alibaba.fastjson.JSON;
import com.ld.utils.IdWorker;
import com.ldg.seckill.entity.SeckillStatus;
import com.ldg.seckill.entity.TbSeckillGoods;
import com.ldg.seckill.entity.TbSeckillOrder;
import com.ldg.seckill.service.MultiThreadingCreateOrder;
import com.ldg.seckill.service.TbSeckillGoodsService;
import com.ldg.seckill.service.TbSeckillOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * @Author: Liudao
 * @Date: 2022-10-22-15:25
 * @Description:
 */
@Service
public class MultiThreadingCreateOrderImpl implements MultiThreadingCreateOrder {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IdWorker idWorker;
    @Autowired
    private TbSeckillGoodsService goodsService;

    //异步下单
    @Override
    @Async
    public void CreatOrder() {
        //1.1 从链表右侧取出秒杀用户状态信息
        String s = redisTemplate.boundListOps("SeckillOrderQueue").rightPop();
        //1.2 转换为SecKillStatus
        SeckillStatus seckillStatus = JSON.parseObject(s, SeckillStatus.class);

        //1.3 避免重复超卖
        assert seckillStatus != null;
        String rightPop = redisTemplate.boundListOps("SeckillGoodsCountList_" + seckillStatus.getSecKillId()).rightPop();
        if(rightPop == null){
            //1.3.1 清空秒杀状态
            clearQueue(seckillStatus.getUsername());
            return ;
        }

        //1.4 根据商品id从redis中查询出秒杀商品
        Long secKillId = seckillStatus.getSecKillId();
        BoundHashOperations<String, String, String> boundHashOperations = redisTemplate.boundHashOps("seckillGoods_" + seckillStatus.getTime());
        String secKillStr = boundHashOperations.get(secKillId);
        TbSeckillGoods seckillGoods = JSON.parseObject(secKillStr, TbSeckillGoods.class);

        //1.5 判断秒杀商品是否存在
        if(seckillGoods == null || seckillGoods.getStockCount() == 0){
            throw new RuntimeException("商品己售罄");
        }
        //1.6 构造秒杀订单对象
        TbSeckillOrder seckillOrder = new TbSeckillOrder();
        long id = idWorker.nextId();
        seckillOrder.setId(id);
        seckillOrder.setCreateTime(new Date());
        seckillOrder.setMoney(seckillGoods.getCostPrice());
        seckillOrder.setStatus("0");            //未支付
        seckillOrder.setUserId(seckillStatus.getUsername());
        seckillOrder.setSeckillId(seckillStatus.getSecKillId());
        //1.7 将订单放到redis中
        redisTemplate.boundHashOps("SeckillOrder").put(seckillStatus.getUsername(),JSON.toJSONString(seckillGoods));

        //1.8 进行精准控制
        Long count = redisTemplate.boundHashOps("SeckillGoodsCount").increment(secKillId + "", -1);
        seckillGoods.setStockCount(new Integer(count + ""));

        //1.9 其它情况
        //1.9.1 如果库存量不足
        if(seckillGoods.getStockCount() < 0){
            //1.9.2 更新到数据库中
            goodsService.updateById(seckillGoods);
            //1.9.3 从redis中删除此商品
            redisTemplate.boundHashOps("seckillGoods_"+seckillStatus.getTime()).delete(seckillGoods.getId() + "");
        }else{  // 否则，重新保存回redis
            redisTemplate.boundHashOps("seckillGoods_"+seckillStatus.getTime()).put(seckillGoods.getId() + "", JSON.toJSONString(seckillGoods));
        }
        //1.10 重新修改支付备份状态
        seckillStatus.setMoney(seckillGoods.getCostPrice().floatValue());       //修改订单金额
        seckillStatus.setStatus(2);     //代表正在等待支付
        seckillStatus.setOrderId(id);    //订单id
        redisTemplate.boundHashOps("UserQueueStatus").put(seckillStatus.getUsername(),JSON.toJSONString(seckillStatus));

    }
    // 清空秒杀状态值
    @Override
    public void clearQueue(String username) {
        //1. 清理排队的数量
        redisTemplate.boundHashOps("UserQueueCount").delete(username);
        //2. 清除排队的状态值
        redisTemplate.boundHashOps("UserQueueStatus").delete(username);
    }
}

